package org.example.pingpong.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.example.pingpong.common.exception.ForbiddenException;
import org.example.pingpong.domain.dto.UserFormDTO;
import org.example.pingpong.domain.po.Application;
import org.example.pingpong.domain.po.User;
import org.example.pingpong.domain.vo.Result;
import org.example.pingpong.domain.vo.UserVO;
import org.example.pingpong.service.ApplicationService;
import org.example.pingpong.service.EmailService;
import org.example.pingpong.service.RedisService;
import org.example.pingpong.service.UserService;
import org.example.pingpong.utils.JwtUtil;
import org.example.pingpong.utils.ThreadLocalUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.Pattern;
import java.util.HashMap;
import java.util.Map;

/**
 * 用户管理接口
 */
@Api(tags = "01.用户管理接口")
@RestController
@Validated
@Slf4j
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private EmailService emailService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private ApplicationService applicationService;

    /**
     * 发送邮箱验证码用于注册
     *
     * @param email 用户邮箱
     * @return 返回发送结果
     */
    @ApiOperation("发送邮箱验证码_注册")
    @PostMapping("/emailmsg/signup")
    public Result sendcode_signup(@RequestParam("email") String email) {
        Result result = emailService.SignupCodeMail(email);
        if (result.getStatus() == 200)
            return Result.success(result.getData());
        else
            return Result.fail(result.getStatus(), result.getMsg());
    }

    /**
     * 发送邮箱验证码用于找回密码
     *
     * @param email 用户邮箱
     * @return 返回发送结果
     */
    @ApiOperation("发送邮箱验证码_找回密码")
    @PostMapping("/emailmsg/retrieve")
    public Result sendcode_retrieve(@RequestParam("email") String email) {
        Result result = emailService.RetrieveCodeMail(email);
        if (result.getStatus() == 200)
            return Result.success(result.getData());
        else
            return Result.fail(result.getStatus(), result.getMsg());
    }

    /**
     * 用户注册接口，包含数据验证、用户创建及JWT Token生成
     *
     * @param validator 用户数据
     * @return 注册结果
     */
    @ApiOperation("用户注册接口")
    @PostMapping("/signup")
    public Result signup(@RequestBody @Validated UserFormDTO validator) {
        System.out.println(userService.encryptPassword(validator.getPassword()));
        try {
            // 验证用户数据合法性
            Result result = userService.userDataCheck(validator);
            if (result.getStatus() == 200) {
                // 创建新用户
                UserFormDTO createdUser = userService.createUser(validator);

                // 生成JWT Token
                Map<String, Object> map = new HashMap<>();
                map.put("username", validator.getUsername());
                map.put("id", validator.getId());

                // 生成Token并保存到Redis
                String token = JwtUtil.genToken(map);
                redisService.setJwtToken(token, 3 * 24 * 60 * 60);

                // 返回成功结果并包含Token
                return Result.success(new UserVO(token, 0));
            }
            return result;
        } catch (ForbiddenException e) {
            // 捕获ForbiddenException并返回错误
            return Result.fail(403, e.getMessage());
        } catch (Exception e) {
            // 捕获其它异常并返回500错误
            return Result.fail(500, "注册失败，请稍后再试：" + e.getMessage());
        }
    }

    /**
     * 用户登录接口，校验用户名和密码，生成JWT Token
     *
     * @param username 用户名
     * @param pwd      用户密码
     * @return 登录结果
     */
    @ApiOperation("用户登录接口")
    @GetMapping("/login")
    public Result login(@Pattern(regexp = "^\\S{5,16}$") @RequestParam("USERNAME") String username,
                        @Pattern(regexp = "^\\S{5,16}$") @RequestParam("PASSWORD") String pwd) {

        User u = new User();
        u.setUsername(username);

        QueryWrapper<User> wrapper = new QueryWrapper<>(u);
        User user = userService.getOne(wrapper);
        if (user == null) return Result.fail(501, "账号不存在");
        if (!userService.checkUserPassword(pwd, user.getPassword())) return Result.fail(502, "密码错误");

        // 生成JWT Token并存储到Redis
        Map<String, Object> map = new HashMap<>();
        map.put("username", username);
        map.put("id", user.getId());

        String token = JwtUtil.genToken(map);
        redisService.setJwtToken(token, 3 * 24 * 60 * 60);

        return Result.success(new UserVO(token, user.getPower()));
    }

    /**
     * 用户注销接口，校验密码并清除JWT Token
     *
     * @param pwd 用户密码
     * @return 注销结果
     */
    @ApiOperation("用户注销接口")
    @DeleteMapping("/delete")
    public Result delete(@Pattern(regexp = "^\\S{5,16}$") @RequestParam("PASSWORD") String pwd, HttpServletRequest request) {

        Map<String, Object> map = ThreadLocalUtil.get();
        int id = (int) map.get("id");

        if (!userService.checkUserPassword(pwd, userService.getById(id).getPassword()))
            return Result.fail(502, "密码错误");
        userService.removeById(id);

        // 删除JWT Token
        redisService.delJwtToken(request.getHeader("Authorization"));
        return Result.success(null);
    }

    /**
     * 用户修改密码接口，校验旧密码并更新为新密码
     *
     * @param oldPwd 旧密码
     * @param newPwd 新密码
     * @return 修改密码结果
     */
    @ApiOperation("用户改密接口")
    @PutMapping("/fixpwd")
    public Result fixpwd(@Pattern(regexp = "^\\S{5,16}$") @RequestParam("OLD_PASSWORD") String oldPwd,
                         @Pattern(regexp = "^\\S{5,16}$") @RequestParam("NEW_PASSWORD") String newPwd,
                         HttpServletRequest request) {

        Map<String, Object> map = ThreadLocalUtil.get();
        int id = (int) map.get("id");
        if (!userService.checkUserPassword(oldPwd, userService.getById(id).getPassword()))
            return Result.fail(502, "密码错误");

        newPwd = userService.encryptPassword(newPwd);
        UpdateWrapper<User> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", id);
        wrapper.set("password", newPwd);
        userService.update(wrapper);

        return Result.success(null);
    }

    /**
     * 用户自动登录接口，生成新的JWT Token
     *
     * @return 新的JWT Token
     */
    @ApiOperation("用户自动登录接口")
    @GetMapping("/autologin")
    public Result autologin() {
        Map<String, Object> map = ThreadLocalUtil.get();
        return Result.success(new UserVO(redisService.newJwtToken(), userService.getById((Integer) map.get("id")).getPower()));
    }

    /**
     * 用户修改个人信息接口
     *
     * @param userFormDTO 用户信息
     * @return 修改结果
     */
    @ApiOperation("用户修改信息接口")
    @PostMapping("/edit")
    public Result edit(@RequestBody @Validated UserFormDTO userFormDTO) {
        Map<String, Object> map = ThreadLocalUtil.get();
        User temp = new User();
        temp.setId((Integer) map.get("id"));
        UpdateWrapper<User> wrapper = new UpdateWrapper<>(temp);

        User u = new User();
        u.setId(null);
        u.setPower(null);
        u.setPassword(null);
        u.setUsername(null);
        BeanUtils.copyProperties(userFormDTO, u);

        userService.update(u, wrapper);
        return Result.success(null);
    }

    /**
     * 用户找回密码接口，通过邮箱和验证码找回密码
     *
     * @param email  用户邮箱
     * @param code   验证码
     * @param newPwd 新密码
     * @return 找回密码结果
     */
    @ApiOperation("用户找回密码接口")
    @PutMapping("/findpwd")
    public Result findPwd(@RequestParam("email") String email, @RequestParam("code") String code, @RequestParam("newPWD") String newPwd) {
        Result result = userService.EmailDataCheck(email, code);
        if (result.getStatus() == 200) {
            return userService.findPassword(email, newPwd);
        }
        return Result.fail(result.getStatus(), result.getMsg());
    }

    /**
     * 获取用户相关的申请记录列表
     *
     * @param PAGE 页码
     * @param SIZE 每页条数
     * @return 申请记录列表
     */
    @ApiOperation("用户申请列表接口")
    @GetMapping("/list")
    public Result list(@RequestParam Integer PAGE, @RequestParam Integer SIZE) {
        Map<String, Object> map = ThreadLocalUtil.get();
        QueryWrapper<Application> wrapper = new QueryWrapper<>();
        wrapper.eq("id", map.get("id"));

        return Result.success(applicationService.page(new Page<>(PAGE, SIZE), wrapper).getRecords());
    }

    /**
     * 获取用户分数排行榜
     *
     * @param PAGE 页码
     * @param SIZE 每页条数
     * @return 申请记录列表
     */
    @ApiOperation("用户排行榜接口")
    @GetMapping("/ratebyuser")
    public Result ratebyuser(@RequestParam Integer PAGE, @RequestParam Integer SIZE) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(User::getRating);
        return Result.success(userService.page(new Page<>(PAGE, SIZE), wrapper).getRecords());
    }
}
